#include "AreaDialog.h"

/*********************| marcos |*********************/

#define ROLL_BG_W				370
#define ROLL_BG_H				348
#define ROLL_BG_SIZE				CCSizeMake(ROLL_BG_W, ROLL_BG_H)
#define ROLL_TEXT_COLOR				ccBLACK
#define ROLL_CELL_W				135
#define ROLL_CELL_H				62
#define SHOW_CELL_CNT				3

/*********************| AreaRollLayer class |*********************/

class AreaRollLayer : public CCLayer , public CCTableViewDelegate,
		public CCTableViewDataSource
{
public:
					AreaRollLayer();
					~AreaRollLayer();
public:
	static AreaRollLayer*		create(const int provinceId);
public:
	bool				init(const area_list_p pAreaList, bool autoClean);
public:
	bool				ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
	void				ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
	void				ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
	void				ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
	void 				scrollViewDidZoom(CCScrollView* view) {}
	void 				scrollViewDidScroll(CCScrollView* view) {}
	void 				tableCellTouched(CCTableView* table, CCTableViewCell* cell);
	CCSize 				tableCellSizeForIndex(CCTableView *table, unsigned int idx);
	unsigned int 			numberOfCellsInTableView(cocos2d::extension::CCTableView *table);
	CCTableViewCell* 		tableCellAtIndex(CCTableView *table, unsigned int idx);
private:
	/**
	 * @brief adjustViewToIndex 将tableview定位到需要的位置
	 * @param idx 如果force是true的时候该参数有效
	 * @param force 是否强制设定位置。false状态将执行一次可能的回调
	 */
	void				adjustViewToIndex(const int idx, const bool force);
public:
	area_list_p			_pAreaList;
	int				_index;
	SEL_CallFunc			_selector;
	CCObject*			_sender;
private:
	bool				_bClean;
	CCTableView*			_rollTableView;
	float				_startOffY;
	CCPoint				_touchPos;
	CCRect				_tableRect;
};


AreaRollLayer::AreaRollLayer() : _pAreaList(NULL), _index(0), _bClean(true)
{
	_sender = NULL;
	_selector = NULL;
}

AreaRollLayer::~AreaRollLayer()
{
	if (_bClean) {
		free_area_list(_pAreaList);
	}
}

AreaRollLayer*AreaRollLayer::create(const int provinceId)
{
	if (provinceId < 0) {
		return NULL;
	}
	AreaRollLayer* ret = new AreaRollLayer();
	area_list_p p;
	bool clean;
	if (0 == provinceId) {
		p = provinces;
		clean = false;
	} else {
		p = init_sub_area_list(provinceId);
		clean = true;
	}
	if (p && ret && ret->init(p, clean)) {
		ret->autorelease();
		return ret;
	} else {
		delete ret;
		if (provinceId != 0) {
			free_area_list(p);
		}
		return NULL;
	}
}

bool AreaRollLayer::init(const area_list_p pAreaList, bool autoClean)
{
	bool bRet = false;
	do {
		CC_BREAK_IF(!pAreaList);
		CC_BREAK_IF(!CCLayer::init());
		_bClean = autoClean;
		_pAreaList = pAreaList;
		/* 定位滑动区域啊 */
		_rollTableView = CCTableView::create(
					 this,
		                         CCSizeMake(ROLL_CELL_W, ROLL_CELL_H * SHOW_CELL_CNT));
		CC_BREAK_IF(!_rollTableView);
		_rollTableView->setDirection(kCCScrollViewDirectionVertical);
		_rollTableView->setPosition(ccp(0,0));
		_rollTableView->setDelegate(this);
		_rollTableView->setVerticalFillOrder(kCCTableViewFillTopDown);
		_startOffY = -_rollTableView->getContentSize().height +
			     ROLL_CELL_H * SHOW_CELL_CNT - ROLL_CELL_H;
		adjustViewToIndex(0, true);
		this->addChild(_rollTableView);
		bRet = true;
	}while(0);
	return bRet;
}

bool AreaRollLayer::ccTouchBegan(CCTouch* pTouch, CCEvent* pEvent)
{
	if (!this->isVisible()) {
		return false;
	}
	_touchPos = pTouch->getLocation();
	_tableRect = CCRectMake(this->getPositionX(), this->getPositionY(),
	                        _rollTableView->getViewSize().width, _rollTableView->getViewSize().height);
	if (_tableRect.containsPoint(_touchPos)) {
		return true;
	}
	return false;
}

void AreaRollLayer::ccTouchEnded(CCTouch* pTouch, CCEvent* pEvent)
{
	adjustViewToIndex(0, false);
}

void AreaRollLayer::ccTouchMoved(CCTouch* pTouch, CCEvent* pEvent)
{
	CCPoint thisPos = pTouch->getLocation();
	float move = thisPos.y - _touchPos.y + _rollTableView->getContentOffset().y;
	_rollTableView->setContentOffset(ccp(0,  move), false);
	_touchPos = thisPos;
}

void AreaRollLayer::ccTouchCancelled(CCTouch* pTouch, CCEvent* pEvent)
{
	adjustViewToIndex(0, false);
}

void AreaRollLayer::tableCellTouched(CCTableView* table, CCTableViewCell* cell)
{
	CCLog("---------%u", cell->getIdx());
}

CCSize AreaRollLayer::tableCellSizeForIndex(CCTableView* table, unsigned int idx)
{
	return CCSizeMake(ROLL_CELL_W, ROLL_CELL_H);
}

unsigned int AreaRollLayer::numberOfCellsInTableView(CCTableView* table)
{
	return _pAreaList->size;
}

CCTableViewCell* AreaRollLayer::tableCellAtIndex(CCTableView* table, unsigned int idx)
{
	CCTableViewCell *cell = table->dequeueCell();
	CCLabelTTF* strLbl = NULL;
	char tmp[19] = {0};
	strncpy(tmp, _pAreaList->area[idx].name, 18);
	if (strlen(_pAreaList->area[idx].name) > 18) {
		strncpy(tmp + 15,"…", 3);
	}
	if (!cell) {
		cell = new CCTableViewCell();
		cell->autorelease();
		strLbl = CCLabelTTF::create(tmp, "DroidSansFallbackFull", ROLL_CELL_H / 3);
		strLbl->setAnchorPoint(ccp(0, 0.5));
		strLbl->setPosition(ccp(10, ROLL_CELL_H / 2));
		strLbl->setColor(ROLL_TEXT_COLOR);
		cell->addChild(strLbl, 0, 0);
	} else {
		strLbl = (CCLabelTTF*)cell->getChildByTag(0);
		strLbl->setString(tmp);
	}
	return cell;
}

void AreaRollLayer::adjustViewToIndex(const int idx, const bool force)
{
	float offsetY = _startOffY;
	if (idx < _pAreaList->size && force) {
		_index = idx;
		offsetY += _index * ROLL_CELL_H;
	} else {
		offsetY = _rollTableView->getContentOffset().y - offsetY;
		int tmpIdx = (int)(offsetY / ROLL_CELL_H + 0.5f);
		if (tmpIdx < 0) {
			tmpIdx = 0;
			offsetY =  _startOffY;
		} else if (tmpIdx >= _pAreaList->size) {
			tmpIdx = _pAreaList->size - 1;
			offsetY = ROLL_CELL_H;
		} else {
			offsetY = tmpIdx * ROLL_CELL_H + _startOffY;
		}
		if (tmpIdx != _index) {
			_index = tmpIdx;
			if (_sender && _selector) {
				(_sender->*_selector)();
			}
		}
	}
	_rollTableView->setContentOffset( ccp(0,offsetY), true);
}

/*********************| funcs in AreaDialog |*********************/

AreaDialog::AreaDialog()
{
	_rollBgBatch = NULL;
	_leftRollLayer = _rightRollLayer = NULL;
}

AreaDialog::~AreaDialog()
{ }

bool AreaDialog::init()
{
	bool bRet = false;
	do {
		CC_BREAK_IF(!YesNoPortrol::init("选择城市", ROLL_BG_SIZE));

		/* scroll layer && 显示两个列表 */
		_rollBgBatch = CCSpriteBatchNode::create("dialog/roll_bg.png", 2);
		CC_BREAK_IF(!_rollBgBatch);
		_rollBgBatch->setPosition(CCPointZero);
		this->addChild(_rollBgBatch);

		CCSprite* roll = CCSprite::createWithTexture(_rollBgBatch->getTexture());
		CCSprite* line = (CCSprite*)_lineBatch->getChildByTag(1);
		CC_BREAK_IF(!roll);
		roll->setAnchorPoint(CCPointZero);
		roll->setPosition(ccp(_bg->boundingBox().getMinX() + 37,
				      line->boundingBox().getMaxY() + 8));
		_rollBgBatch->addChild(roll, 0, 0);

		_leftRollLayer = AreaRollLayer::create(0);
		CC_BREAK_IF(!_leftRollLayer);
		_leftRollLayer->setAnchorPoint(CCPointZero);
		_leftRollLayer->setPosition(ccp(roll->getPositionX(), roll->getPositionY() +6));
		this->addChild(_leftRollLayer);
		this->addACanTouchLayer(_leftRollLayer);

		roll = CCSprite::createWithTexture(_rollBgBatch->getTexture());
		CC_BREAK_IF(!roll);
		roll->setAnchorPoint(ccp(1, 0));
		roll->setPosition(ccp(_bg->boundingBox().getMaxX() - 37,
				      line->boundingBox().getMaxY() + 8));
		_rollBgBatch->addChild(roll, 0, 1);

		_rightRollLayer = AreaRollLayer::create(_leftRollLayer->_pAreaList->area->id);
		CC_BREAK_IF(!_rightRollLayer);
		_rightRollLayer->setAnchorPoint(CCPointZero);
		_rightRollLayer->setPosition(ccp(roll->boundingBox().getMinX(), _leftRollLayer->getPositionY()));
		this->addChild(_rightRollLayer);
		this->addACanTouchLayer(_rightRollLayer);
		_leftRollLayer->_sender = (CCObject*)this;
		_leftRollLayer->_selector = callfunc_selector(AreaDialog::updateRightRollLayer);

		bRet = true;
	}while(0);
	return bRet;
}

const size_t AreaDialog::getRetCode()
{
	if (_rightRollLayer) {
		return _rightRollLayer->_pAreaList->area[_rightRollLayer->_index].id;
	}
}

void AreaDialog::updateRightRollLayer()
{
	AreaRollLayer* layer = AreaRollLayer::create(_leftRollLayer->_pAreaList->area[_leftRollLayer->_index].id);
	if (layer) {
		layer->setAnchorPoint(_rightRollLayer->getAnchorPoint());
		layer->setPosition(_rightRollLayer->getPosition());
		this->removeCanTouchLayer(_rightRollLayer);
		_rightRollLayer->removeFromParentAndCleanup(true);
		_rightRollLayer = layer;
		this->addChild(_rightRollLayer);
		this->addACanTouchLayer(_rightRollLayer);
	}

}
